%{
   #include "ts.h" /* Contains definition of ‘symrec'. */

   enum yytokentype {
      VARIABLE          = 256,
   ENTERO            = 257,
   IF                = 258,
   ELSE              = 259,
   SWITCH            = 260,
   CASE              = 261,
   BREAK             = 262,
   DEFAULT           = 263,
   DO                = 264,
   WHILE             = 265,
   FOR               = 266,
   OPASIG            = 267,
   OPLOG             = 268,
   MEN               = 269,
   MEI               = 270,
   MAY               = 271,
   MAI               = 272,
   IGU               = 273,
   NOT               = 274,
   DIF               = 275,
   SENTENCIA         = 276,
   INCREMENTO        = 277,
   DECREMENTO        = 278,
   FIN_SENTENCIA     = 279,
   PARENTESIS_ABRE   = 280,
   PARENTESIS_CIERRA = 281,
   LLAVE_ABRE        = 282,
   LLAVE_CIERRA      = 283,

   };

   float yylval;

	/* Tabla de símbolos: Lista de nodos 'nodo_ts' */
	token *ts;
%}

obviar         [" "\t\n]+
letra_         [A-Za-z_]
digito         [0-9]
variable       {letra_}({letra_}|{digito})*
entero         [+-]?{digito}+(\.{digito}*)?(E[+-]?{digito}+)?
sentencia      [;]
incremento     [++]
decremento     [--]

%%

{obviar}       { }
if             { printf("<IF>\n");}
else           { printf("<ELSE>\n");}
switch         { printf("<SWITCH>\n");}
case           { printf("<CASE>\n");}
break          { printf("<BREAK>\n");}
default        { printf("<DEFAULT>\n");}
do             { printf("<DO>\n");}
while          { printf("<WHILE>\n");}
for            { printf("<FOR>\n");}
{variable}     { return VARIABLE; }
{entero}       { yylval = atof(yytext); return ENTERO; }
"<="           { yylval = MEI; return(OPLOG); }
">"            { yylval = MAY; return(OPLOG); }
">="           { yylval = MAI; return(OPLOG); }
"<"            { yylval = MEN; return(OPLOG); }
"!="           { yylval = DIF; return(OPLOG); }
"!"            { yylval = NOT; return(OPLOG); }
"=="           { yylval = IGU; return(OPLOG); }
"="            { return OPASIG; }
"++"           { return INCREMENTO; }
"--"           { return DECREMENTO; }
";"            { return FIN_SENTENCIA; }
"("            { return PARENTESIS_ABRE; }
")"            { return PARENTESIS_CIERRA; }
"{"            { return LLAVE_ABRE; }
"}"            { return LLAVE_CIERRA; }

%%

/* Tabla de símbolos: Lista de nodos tipo token. */
token *ts;

/*
   Inicialización de la tabla de símbolos:
   1.- Copiado de las palabras reservadas del lenguaje.
*/

void init_table (void) {
   int i;
   token *ptr;

   ptr = putToken ("if", IF, 0.0);
   ptr = putToken ("else", ELSE, 0.0);
   ptr = putToken ("switch", SWITCH, 0.0);
   ptr = putToken ("case", CASE, 0.0);
   ptr = putToken ("break", BREAK,0.0);
   ptr = putToken ("default", DEFAULT, 0.0);
   ptr = putToken ("do", DO, 0.0);
   ptr = putToken ("while", WHILE, 0.0);
   ptr = putToken ("for", FOR, 0.0);
}

token * putToken (char const *name, int type, double value) {
   token *ptr;
   ptr = (token *) malloc (sizeof (token));

   ptr->nombre = (char *) malloc (strlen (name) + 1);
   strcpy (ptr->nombre, name);
   ptr->tipo = type;
   ptr->valor.numero = value;

   ptr->next = (struct token *) ts;
   ts = ptr;
   return ptr;
}

token * getToken (char const *name) {
   token *ptr;
   for (ptr = ts; ptr != (token *) 0; ptr = (token *)ptr->next)
      if (strcmp (ptr->nombre, name) == 0)
         return ptr;
   return 0;
}

void deleteTS() {
   token *ptr;

   while(ts != (token *) 0) {
      ptr = ts->next;
      free(ts);
      ts = ptr;
   }
}

void showTS() {
   token *ptr = ts;

   printf("\nTokens almacenados en la tabla de símbolos:\n");

   while(ptr != (token *) 0) {
      if(ptr->tipo == IF)
    {
      printf("<IF>");
    }
    else
    if(ptr->tipo == ELSE)
    {
      printf("<ELSE>");
    }
    else
      if(ptr->tipo == SWITCH)
    {
      printf("<SWITCH>");
    }
    else
    if(ptr->tipo == CASE)
    {
      printf("<CASE>");
    }
    else
    if (ptr->tipo == BREAK)
    {
      printf("<BREAK>");
    }
    else
    if (ptr->tipo == DEFAULT)
    {
      printf("<DEFAULT>");
    }
    else
    if (ptr->tipo == DO)
    {
      printf("<DO>");
    }
    else
    if (ptr->tipo == WHILE)
    {
      printf("<WHILE>");
    }
    else
      if (ptr->tipo == FOR) {
         printf("<FOR>");
      } else
      if (ptr->tipo == VARIABLE) {
         printf("<VARIABLE,%s>",ptr->nombre);
      } else {
         printf("Error: Tipo de token desconocido.");
      }
      ptr = ptr->next;
      printf("\n");
   }
   printf("\n");
}

main(int argc, char **argv) {
   int tok;

   if(argc > 1) {
      if(!(yyin = fopen(argv[1], "r"))) {
         printf("ERROR: El archivo de entrada no pudo ser leído.\n");
         exit(0);
      }
   }

   init_table ();

   while(tok=yylex()) {
      if(tok== INCREMENTO) {
         printf("<INCREMENTO>");
      } else
      if(tok==OPLOG) {
         printf("<OPLOG,%i>",(int)yylval);
      } else
      if(tok==OPASIG) {
         printf("<OPASIG>");
      } else
      if(tok== DECREMENTO) {
         printf("<DECREMENTO>");
      } else
      if(tok== FIN_SENTENCIA) {
         printf("<FIN_SENTENCIA>");
      } else
      if(tok== PARENTESIS_ABRE) {
         printf("<PARENTESIS_ABRE>");
      } else
      if(tok== PARENTESIS_CIERRA) {
         printf("<PARENTESIS_CIERRA>");
      } else
      if(tok== LLAVE_ABRE) {
         printf("<LLAVE_ABRE>");
      } else
      if(tok== LLAVE_CIERRA) {
         printf("<LLAVE_CIERRA>");
      } else
      if(tok==ENTERO) {
         printf("<ENTERO,%.2f>",yylval);
      } else
      if(tok==VARIABLE) {
         token *t;
         t = getToken (yytext);
         if (t == 0) {
            t = putToken (yytext, VARIABLE, 0.0);
            printf("<VARIABLE,%s>",yytext);
         } else {
            if (t->tipo == IF) {
             printf("<IF>");
           } else
           if (t->tipo == ELSE) {
              printf("<ELSE>");
           } else
           if (t->tipo == SWITCH) {
              printf("<SWITCH>");
           } else
           if (t->tipo == CASE) {
              printf("<CASE>");
           } else
           if (t->tipo == BREAK) {
              printf("<BREAK>");
           } else
           if (t->tipo == DEFAULT) {
              printf("<DEFAULT>");
           }else
           if (t->tipo == DO) {
              printf("<DO>");
           } else
           if (t->tipo == WHILE) {
              printf("<WHILE>");
           } else
           if (t->tipo == FOR) {
               printf("<FOR>");
            } else {
               printf("<VARIABLE,%s>",yytext);
            }
         }
      } else {
         printf("¡ERROR! Cadena no reconocida: %s", yytext);
      }

      printf("\n");
   }

   showTS();
   deleteTS();
}
